package com.aletto.general_store.ui.popup;

import android.content.Context;
import android.content.Intent;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

import com.aletto.general_store.R;
import com.aletto.general_store.data.DataRepository;
import com.aletto.general_store.data.entities.WalletAccount;
import com.aletto.general_store.data.model.Address;
import com.aletto.general_store.data.model.Goods;
import com.aletto.general_store.data.model.OrderCreate;
import com.aletto.general_store.data.model.Response;
import com.aletto.general_store.presenters.core.SimpleTemplate;
import com.aletto.general_store.presenters.views.OrderGoodsBuyView;
import com.aletto.general_store.ui.activities.AddressAddActivity;
import com.aletto.general_store.ui.activities.AddressManageActivity;
import com.aletto.general_store.data.ERC20ServiceAbi;
import com.aletto.general_store.utils.LocalConfigStore;
import com.aletto.general_store.utils.Login;
import com.aletto.general_store.utils.ToastUtils;
import com.aletto.general_store.utils.XHelper;
import com.aletto.general_store.utils.event.UseAddressEvent;
import com.aletto.general_store.utils.image.GlideApp;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.core.BottomPopupView;
import com.sisyphus.spinach.core.INetTask;
import com.sisyphus.spinach.network.presenters.NetSingleTask;
import com.sisyphus.spinach.network.utils.RxUtil;
import com.sisyphus.spinach.network.views.ToastView;
import com.sisyphus.spinach.utils.RichTextHelper;

import androidx.annotation.NonNull;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.ObservableSource;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Function;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.core.methods.response.EthSendTransaction;

import java.math.BigDecimal;
import java.util.List;

public class GoodsPopup extends BottomPopupView {

    private Goods goods;
    private Address address;

    private Button confirm_button;
    private TextView tv_buy_number;

    private WalletAccount wallet;

    public GoodsPopup(@NonNull Context context) {
        super(context);
    }

    public GoodsPopup(@NonNull Context context, Goods goods) {
        super(context);
        this.goods = goods;
        EventBus.getDefault().register(this);
    }

    @Override
    protected int getImplLayoutId() {
        return R.layout.popup_goods;
    }

    @Override
    protected void onCreate() {
        super.onCreate();
        wallet = LocalConfigStore.getInstance().getWallet();

        View layout_address = findViewById(R.id.layout_address);
        layout_address.setVisibility(goods.type == 1 ? View.GONE : View.VISIBLE); // 1为数字商品，2为实物

        TextView addAddressText = findViewById(R.id.tv_add_address);
        TextView tv_goods_price = findViewById(R.id.tv_goods_price);
        TextView tv_price_unit = findViewById(R.id.tv_price_unit);
        TextView tv_goods_price_origin = findViewById(R.id.tv_goods_price_origin);
        TextView tv_goods_title = findViewById(R.id.tv_goods_title);
        confirm_button = findViewById(R.id.confirm_button);
        ImageView goods_cover = findViewById(R.id.goods_cover);

        tv_buy_number = findViewById(R.id.tv_buy_number);
        tv_buy_number.setText(String.valueOf(1)); // 购买数量

        ImageView view_decrease = findViewById(R.id.view_decrease);
        view_decrease.setOnClickListener(v -> { // 减
            int parsed = Integer.parseInt(tv_buy_number.getText().toString());
            if (parsed <= 1) return;
            tv_buy_number.setText(String.valueOf(parsed - 1));
            renderPrice(parsed - 1);
        });

        ImageView view_increase = findViewById(R.id.view_increase);
        view_increase.setOnClickListener(v -> { // 加
            int parsed = Integer.parseInt(tv_buy_number.getText().toString());
            if (parsed >= goods.stock) return;
            tv_buy_number.setText(String.valueOf(parsed + 1));
            renderPrice(parsed + 1);
        });

        tv_buy_number.addTextChangedListener(new TextWatcher() {

            @Override
            public void afterTextChanged(Editable s) {
                if (s != null && s.length() > 0) {
                    int parsed = Integer.parseInt(s.toString());
                    if (parsed <= 1) {
                        view_decrease.setImageResource(R.mipmap.ic_number_decrease);
                        view_increase.setImageResource(R.mipmap.ic_number_add_normal);

                    } else if (parsed >= goods.stock) {
                        view_decrease.setImageResource(R.mipmap.ic_number_decrease_normal);
                        view_increase.setImageResource(R.mipmap.ic_number_add);

                    } else {
                        view_decrease.setImageResource(R.mipmap.ic_number_decrease_normal);
                        view_increase.setImageResource(R.mipmap.ic_number_add_normal);
                    }
                }
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }
        });

        if (goods.goods_img != null && !goods.goods_img.isEmpty()) {
            GlideApp.with(goods_cover)
                    .load(goods.goods_img.get(0))
                    .goodsLeftGrid()
                    .into(goods_cover);
        }

        renderPrice(1); // 默认购买一个

        tv_goods_price.setText(goods.getPrice());
        tv_price_unit.setText(goods.getPriceUnit());
        tv_goods_price_origin.setText(
                RichTextHelper.newBuilder(goods.getOriginal_price() + "\t" + goods.getPriceUnit())
                        .striketrough()
                        .build()
        );

        tv_goods_title.setText(goods.getTitle());

        findViewById(R.id.close_image).setOnClickListener(v -> dismiss());

        addAddressText.setOnClickListener(v -> {
            Context context = v.getContext();
            context.startActivity(new Intent(context, AddressAddActivity.class));
        });

        findViewById(R.id.image_view).setOnClickListener(new Login(v -> {
            Context context = v.getContext();
            context.startActivity(new Intent(context, AddressManageActivity.class));
        }));

        // 立即购买
        confirm_button.setOnClickListener(v -> {
            // 没有地址直接返回
            if (addAddressText.getVisibility() != View.GONE) return;

            ERC20ServiceAbi.balance(Credentials.create(wallet.getPrivateKey()), ERC20ServiceAbi.USDT_CONTRACT_ADDRESS)
                    .filter(balance -> {

                        int number = Integer.parseInt(tv_buy_number.getText().toString());
                        BigDecimal price = new BigDecimal(Float.parseFloat(goods.getPrice()) * number);

                        if (balance.compareTo(price) < 0) {
                            throw new Exception("USDT余额不足");
                        }

                        return true;
                    })
                    .compose(RxUtil.transformer())
                    .subscribe(new Observer<>() {
                        @Override
                        public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {

                        }

                        @Override
                        public void onNext(@io.reactivex.rxjava3.annotations.NonNull BigDecimal balance) {

                            // 调用接口
                            buy(Integer.parseInt(tv_buy_number.getText().toString()));
                        }

                        @Override
                        public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
                            ToastUtils.makeText(e.getMessage());
                        }

                        @Override
                        public void onComplete() {

                        }
                    });
        });

        // 默认地址
        presenter().execute();
    }

    private void renderPrice(int number) {
        SpannableString price = XHelper.toPrice(new BigDecimal(Float.parseFloat(goods.getPrice()) * number));
        String formatString = getResources().getString(R.string.placeholder_goods_details_buy_button);
        confirm_button.setText(String.format(formatString, price, goods.getPriceUnit()));
    }

    private void buy(int number) {
        Observable.create((ObservableOnSubscribe<BigDecimal>) emitter -> {
                    BigDecimal allowance = ERC20ServiceAbi.allowance(
                            ERC20ServiceAbi.USDT_CONTRACT_ADDRESS,
                            wallet.getAddress(),
                            ERC20ServiceAbi.MARKET_CONTRACT_ADDRESS
                    );

                    emitter.onNext(allowance);
                    emitter.onComplete();
                }).compose(RxUtil.transformer())
                .subscribe(new Observer<>() {
                    @Override
                    public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {

                    }

                    @Override
                    public void onNext(@io.reactivex.rxjava3.annotations.NonNull BigDecimal allowance) {
                        BigDecimal price = new BigDecimal(Float.parseFloat(goods.getPrice()) * number);
                        if (allowance.compareTo(price) < 0) { // 授权
                            new XPopup.Builder(getContext())
                                    .asCustom(new ApprovePermissionPopup(getContext(), s -> dismiss()))
                                    .show();
                            return;
                        }

                        // 购买
                        createOrder(number);
                    }

                    @Override
                    public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
                        ToastUtils.makeText(e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });


    }

    private void createOrder(int number) {
        BigDecimal price = new BigDecimal(Float.parseFloat(goods.getPrice()) * number);

        new SimpleTemplate<>() {

            @Override
            public INetTask.View<Object> view() {
                return new ToastView<>(getContext(), new OrderGoodsBuyView(getContext(), goods, number) {
                    @Override
                    public void success(Object data) {
                        super.success(data);
                        dismiss();
                    }
                });
            }

            @Override
            public INetTask.Presenter<Object, INetTask.View<Object>> presenter() {
                return new NetSingleTask<>(
                        DataRepository.getInstance()
                                .createOrder(goods.id, address.getId(), number)
                                .flatMap((Function<Response<OrderCreate>, ObservableSource<Response<OrderCreate>>>) response -> {

                                    OrderCreate data = response.getData();

                                    EthSendTransaction ethSendTransaction = ERC20ServiceAbi.buy(
                                            price,
                                            data.order_id,
                                            number,
                                            goods.type == 1 ? 0 : 1, // 合约端0为数字商品，1为实物产品；服务端1为数字商品，2为实物
                                            Credentials.create(wallet.getPrivateKey()),
                                            goods.wallet_address,
                                            ERC20ServiceAbi.MARKET_CONTRACT_ADDRESS
                                    );

                                    data.hash = ethSendTransaction.getTransactionHash();
                                    data.network = "BNB Smart Chain";
                                    response.setData(data);

                                    return Observable.create(emitter -> {
                                        emitter.onNext(response);
                                        emitter.onComplete();
                                    });
                                })
                                .flatMap(response -> {
                                    OrderCreate data = response.getData();
                                    return DataRepository.getInstance().payOrder(data.order_id, data.network, data.hash);
                                })
                );
            }

        }.execute();

    }


    private SimpleTemplate<List<Address>> presenter() {
        return new SimpleTemplate<>() {
            @Override
            public INetTask.View<List<Address>> view() {
                return new INetTask.View<>() {
                    @Override
                    public void success(List<Address> data) {
                        if (data != null && !data.isEmpty()) {
                            for (Address address : data) {
                                if (address.getIs_default() == 1) {
                                    onEvent(new UseAddressEvent(address));
                                    return;
                                }
                            }

                            onEvent(new UseAddressEvent(data.get(0)));
                        }
                    }
                };
            }

            @Override
            public INetTask.Presenter<List<Address>, INetTask.View<List<Address>>> presenter() {
                return new NetSingleTask<>(DataRepository.getInstance().addressList());
            }
        };
    }

    @Override
    protected void onDismiss() {
        super.onDismiss();
        EventBus.getDefault().unregister(this);
    }

    @Subscribe
    public void onEvent(UseAddressEvent event) {
        address = event.address;
        TextView tv_address = findViewById(R.id.tv_address);
        TextView tv_user_info = findViewById(R.id.tv_user_info);

        tv_address.setText(event.address.getAddress());
        tv_user_info.setText(event.address.getName() + "  " + event.address.getPhone());

        TextView addAddressText = findViewById(R.id.tv_add_address);
        addAddressText.setVisibility(View.GONE);
    }

}
